package com.cqc.common;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.client.HttpClientErrorException;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;
import java.util.StringJoiner;

/**
 * 统一返回结果Result
 */
@RestControllerAdvice(basePackages = {"com.cqc.web"})
public class ExceptionAdviceHandler {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 类型转换错误，比如String》Date
     */
    @ExceptionHandler(ConversionFailedException.class)
    public Result<Void> handleConversionFailedException(ConversionFailedException e) {
        String sb = "原类型[" + e.getSourceType() + "]" +
                "目标 类型[" + e.getTargetType() + "]" +
                "值[" + e.getValue() + "]";
        return Result.errorMsg(sb);
    }

    /**
     * 拦截JSON参数校验
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<Void> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        return Result.errorMsg(this.getErrorMessage(e));
    }

    /**
     * 适用于 @Validated @Valid仅对于表单提交有效，对于以json格式提交将会失效）
     */
    @ExceptionHandler(BindException.class)
    public Result<Void> handleBindException(BindException e) {
        return Result.errorMsg(this.getErrorMessage(e));
    }


    /**
     * 适用于  @NotBlank @NotNull @NotEmpty
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public Result<Void> handleConstraintViolationException(ConstraintViolationException e) {
        StringJoiner joiner = new StringJoiner(";");
        Set<ConstraintViolation<?>> set = e.getConstraintViolations();
        for (ConstraintViolation<?> constraintViolation : set) {
            joiner.add(constraintViolation.getMessage());
        }
        //属性路径=接口.属性名 v.getPropertyPath()=createStu4.name
        //错误信息 v.getMessage()=学生的名字最短3位，最长5位
        //传递的值 v.getInvalidValue()=cc
        //List<String> msgList = set.stream().map(v -> v.getPropertyPath() + "," + v.getMessage() + "," + v.getInvalidValue()).collect(Collectors.toList());
        return Result.errorMsg(joiner.toString());
    }

    /**
     * 通用异常处理方法
     **/
    @ExceptionHandler(Exception.class)
    public Result<Void> handleException(Exception e) {
        logger.warn("### ExceptionAdviceHandler.Exception ", e);
        return Result.errorMsg(e.getMessage());
    }


    @ExceptionHandler(NullPointerException.class)
    public Result<Void> handleNullPointerException(NullPointerException e) {
        logger.warn("### ExceptionAdviceHandler.NullPointerException ", e);
        return Result.error(ResultCodeEnum.NULL_POINT);
    }

    @ExceptionHandler(HttpClientErrorException.class)
    public Result<Void> handleClientErrorException(HttpClientErrorException e) {
        logger.warn("### ExceptionAdviceHandler.HttpClientErrorException ", e);
        return Result.error(ResultCodeEnum.HTTP_CLIENT_ERROR);
    }

    @ExceptionHandler(IndexOutOfBoundsException.class)
    public Result<Void> handleIndexOutOfBoundsException(IndexOutOfBoundsException e) {
        logger.warn("### ExceptionAdviceHandler.IndexOutOfBoundsException ", e);
        return Result.error(ResultCodeEnum.HTTP_CLIENT_ERROR);
    }

//    @ExceptionHandler(BadSqlGrammarException.class)
//    public Result<Void> handleBadSqlGrammarException(BadSqlGrammarException e) {
//        logger.warn("### ExceptionAdviceHandler.BadSqlGrammarException ", e);
//        return Result.errorMsg(e.getMessage());
//    }
//
//    @ExceptionHandler(DataAccessException.class)
//    public Result<Void> handleDataAccessException(DataAccessException e) {
//        logger.warn("### ExceptionAdviceHandler.DataAccessException ", e);
//        return Result.error("数据访问错误");
//    }
//
//    @ExceptionHandler(MybatisPlusException.class)
//    public Result<Void> handleMybatisPlusException(MybatisPlusException e) {
//        logger.warn("### ExceptionAdviceHandler.MybatisPlusException ", e);
//        return Result.errorMsg(e.getMessage());
//    }


    private String getErrorMessage(BindException e) {
        StringJoiner joiner = new StringJoiner(";");
        BindingResult bindingResult = e.getBindingResult();
        List<FieldError> list = bindingResult.getFieldErrors();
        list.forEach(fieldError -> {
            //fieldError.getField()
            joiner.add(fieldError.getDefaultMessage());
        });
        return joiner.toString();
    }
}
